package 反射.代理;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * @Projectname java_based
 * @Filename ProxyTest
 * @Author an
 * @Data 2022/7/27 22:09
 * @Description TODO
 */

/*
* 动态代理的举例
* */


interface Human{
    String getBelief();
    void eat(String food);
}

class HumanUtil{
    public void method1(){
        System.out.println("*******通用方法一******");
    }
    public void method2(){
        System.out.println("*******通用方法二******");
    }
}



//被代理类
class SuperMan implements Human{

    @Override
    public String getBelief() {
        return "T believe I can fly!";
    }

    @Override
    public void eat(String food) {
        System.out.println("我喜欢吃" + food);
    }
}
/**
 * 要想实现动态代理，需要解决的问题？
 * 问题一：如何根据加载到内存中的被代理类，动态的创建一个代理类及其对象。
 * 问题二：当通过代理类的对象调用方法a时，如何动态的去调用被代理类中的同名方法a。
 */


class ProxyFactory{
    //调用此方法，返回一个代理类的对象，解决问题一
    public static Object getProxyInstance(Object obj){//obj:被代理类的对象
        MyInvocationHandle handler = new MyInvocationHandle();

        handler.bind(obj);

        return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),handler);
    }
}


class MyInvocationHandle implements InvocationHandler{

    private Object obj;//需要使用被代理类的对象进行赋值

    public void bind(Object obj){
        this.obj = obj;
    }


    //当我们通过代理类的对象调用方法a时，如何动态的去调用被代理类中的同名方法： invoke()
    //将被代理类要执行的方法a的功能声明在invoke()中
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        HumanUtil util = new HumanUtil();
        util.method1();

        //method：即为代理类对象调用的方法，此方法也就作为了被代理了对象要调用的方法
        //obj：被代理类的对象
        Object returnValue = method.invoke(obj, args);
        util.method2();

        //上述方法的返回值就作为当前类中的invoke()的返回值
        return returnValue;
    }
}


public class ProxyTest {
    public static void main(String[] args) {
        SuperMan superMan = new SuperMan();
        //proxyInstace：被代理的对象
        Human proxyInstance = (Human) ProxyFactory.getProxyInstance(superMan);
        String belief = proxyInstance.getBelief();
        System.out.println(belief);
        proxyInstance.eat("火锅");

        System.out.println("*****************************");

        NickClothFactory nickClothFactory = new NickClothFactory();
        ClothFactory proxyClothFactory = (ClothFactory) ProxyFactory.getProxyInstance(nickClothFactory);
        proxyClothFactory.productCloth();

    }
}
